<?php

namespace App\JsonRPC;

use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Spiral\Config\ConfiguratorInterface;
use Spiral\Prototype\Annotation\Prototyped;

/** @Prototyped(property="jsonrpc") */
class Server
{
    protected ConfiguratorInterface $configurator;
    protected ContainerInterface $container;

    public function __construct(ConfiguratorInterface $configurator, ContainerInterface $container)
    {
        $this->configurator = $configurator;
        $this->container = $container;
    }

    protected function createProcedureFromRequest(Request $request): ?Procedure
    {
        $procedureMap = $this->configurator->getConfig('json-rpc')['procedures'];
        if (!isset($procedureMap[$request->getMethod()])) {
            if ($request->isNotification()) {
                // 对于通知类型的请求，服务端遇到错误的话，应该跳过
                return null;
            }
            throw new InvalidPayloadException("方法[{$request->getMethod()}]不存在");
        }

        $className = $procedureMap[$request->getMethod()];
        /** @var Procedure $obj */
        $obj = $this->container->get($className);
        $obj->setRequestContext($request);
        foreach ($request->getParams() as $k => $v) {
            if (property_exists($obj, $k)) {
                $obj->{$k} = $v;
            }
        }
        return $obj;
    }

    /**
     * 从服务端请求中生成过程实例
     *
     * @param ServerRequestInterface $request
     * @return array|Procedure[]
     * @throws InvalidPayloadException
     */
    public function extractProcedureFromRequest(ServerRequestInterface $request): array
    {
        $jsonrpcRequest = Request::createFromServerRequest($request);

        $procedures = [];
        if ($jsonrpcRequest instanceof BatchRequest) {
            foreach ($jsonrpcRequest->getRequests() as $subRequest) {
                $tmp = $this->createProcedureFromRequest($subRequest);
                if ($tmp) {
                    $procedures[] = $tmp;
                }
            }
        } else {
            $tmp = $this->createProcedureFromRequest($jsonrpcRequest);
            if ($tmp) {
                $procedures[] = $tmp;
            }
        }

        return $procedures;
    }
}
